﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using CommonUtilities.Factories;
using CommonUtilities.SchemaXML.WebThemes;

public class StyleSheetHandler : IHttpHandler
{
   //protected Dictionary<StylesheetCacheKey, string> _cache; // Memory cache of processed stylesheets.

   public StyleSheetHandler()
   {
       //_cache = new Dictionary<StylesheetCacheKey, string>();
   }

   bool IHttpHandler.IsReusable
   {
       get { return true; }
   }

   void IHttpHandler.ProcessRequest(HttpContext context)
   {
       var rawFileName = context.Request.PhysicalPath;
       var rawFileLastModified = File.GetLastWriteTimeUtc(rawFileName);
       var browserName = context.Request.Browser.Browser;
       var browserVersion = new Version(context.Request.Browser.Version);
       XmlFactory<XmlWebThemes> xmlFactory = new XmlFactory<XmlWebThemes>();
       xmlFactory.BaseNamespace = "CommonUtilities.SchemaXML.";
       xmlFactory.OutputFolderName = "App_Data\\WebThemes";
       XmlWebThemes xmlThemes = xmlFactory.CreateXmlRootNode("WebThemes");
       XmlTheme xmlTheme = xmlThemes.XmlTheme(0);

       string processedContent = "";
       var rawContent = File.ReadAllText(rawFileName);
       foreach (object obj in xmlTheme.XmlAttributes.Values)
       {
           XmlAttribute xmlAttribute = obj as XmlAttribute;
           rawContent = rawContent.Replace(xmlAttribute.Variable, xmlAttribute.Value);
       }
       processedContent = rawContent;
       //var newCacheKey = new StylesheetCacheKey(rawFileName, rawFileLastModified, browserName, browserVersion);

       // Check for entry in cache of processed contents of stylesheets that is at least as recent as last
       // modified time of raw file.
       //var cacheEntry = _cache.SingleOrDefault(entry => entry.Key.Equals(newCacheKey) &&
         //  entry.Key.RawFileLastModified >= newCacheKey.RawFileLastModified);
       //string processedContent;
       //if (cacheEntry.Value != null)
       //{
           // Found entry in cache.
         //  processedContent = cacheEntry.Value;
       //}
       //else
       //{
           // Process raw content of stylesheet file.
           //var rawContent = File.ReadAllText(rawFileName);
           //processedContent = ProcessStylesheet(rawContent, browserName, browserVersion);

           // Add processed stylesheet to cache.
           //_cache[newCacheKey] = processedContent;
       //}

       // Write process content of stylesheet to response stream.
       context.Response.ContentType = "text/css";
       context.Response.Output.Write(processedContent);
       context.Response.Flush();
   }

   protected string ProcessStylesheet(string content, string browserName, Version browserVersion)
   {
       // Matches blocks (regions) of commented text (of form "/*{comment}*/").
       var regexComments = new Regex(@"/\*.+?\*/", RegexOptions.Singleline);
       // Matches browser-conditional tags of form "[[?{browser condition} {true result} | {false result}]]".
       var regexTags = new Regex(@"\[\?(?<browser>.+?) +?(?<trueResult>.*?) ?\| ?(?<falseResult>.*?) *?\]",
           RegexOptions.None);

       // Evaluate tags within each comment block.
       var processedContent = regexComments.Replace(content, new MatchEvaluator(blockMatch =>
           {
               var tagCount = 0;
               var evaluatedText = regexTags.Replace(blockMatch.Value, new MatchEvaluator(tagMatch =>
               {
                   tagCount++;

                   // Invert condition if preceded by '!'.
                   var browser = tagMatch.Groups["browser"].Value;
                   bool inverted = false;
                   if (browser[0] == '!')
                   {
                       inverted = true;
                       browser = browser.Substring(1);
                   }
                   return (string.Equals(browser, browserName, StringComparison.InvariantCultureIgnoreCase) ^
                       inverted) ? tagMatch.Groups["trueResult"].Value : tagMatch.Groups["falseResult"].Value;
               }));
               return (tagCount > 0) ? evaluatedText.Substring(2, evaluatedText.Length - 4) : blockMatch.Value;
           }));

       return processedContent;
   }

   protected struct StylesheetCacheKey
   {
       public string StylesheetPath;        // Path of raw stylesheet file.
       public DateTime RawFileLastModified; // Time at which raw file was last modified.
       public string BrowserName;           // Name of browser.
       public Version BrowserVersion;       // Version of browser.

       public StylesheetCacheKey(string stylesheetPath, DateTime rawFileLastModified, string browserName,
           Version browserVersion)
        {
            this.StylesheetPath = stylesheetPath;
            this.RawFileLastModified = rawFileLastModified;
            this.BrowserName = browserName;
            this.BrowserVersion = browserVersion;
        }
 
        public override bool Equals(object obj)
        {
            var objKey = (StylesheetCacheKey)obj;
            return this.StylesheetPath.Equals(objKey.StylesheetPath) &&
                this.BrowserName.Equals(objKey.BrowserName) && this.BrowserVersion.Equals(objKey.BrowserVersion);
        }
 
        public override int GetHashCode()
        {
            return this.StylesheetPath.GetHashCode() ^ this.BrowserName.GetHashCode() ^
                this.BrowserVersion.GetHashCode();
        }
 
        public override string ToString()
        {
            return string.Format("{0}, {1} {2}", this.StylesheetPath, this.BrowserName, 
                this.BrowserVersion.ToString());
        }
    }
}
